﻿<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=Edge">
    <meta name="viewport" content="width=device-width, initial-scale=1" user-scalable="no">
    <title>canvas生成图片</title>
    <link rel="stylesheet" href="css/style.css">
    <script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
</head>

<body>
    <canvas id="canvasScale" width="300" height="300"></canvas>
    <script>
        var util = {
            each: {
                /**
                 * 按照X方向处理图像数据
                 * @param  {Array}    data    图像数据
                 * @param  {Number}   width   图像宽
                 * @param  {Number}   startX  起始点X坐标
                 * @param  {Number}   startY  起始点Y坐标
                 * @param  {Number}   endX    结束点X坐标
                 * @param  {Number}   endY    结束点Y坐标
                 * @param  {Function} handler 处理函数
                 *                            handler(index, x, y)
                 *                            index为当前点在一维数组中的真实位置
                 *                            x为模拟的二维数组中x坐标
                 *                            y为模拟的二维数组中y坐标
                 * @return {Undefined}        没有返回值
                 */
                xDirection: function (data, width, startX, startY, endX, endY, handler) {
                    for (var y = startY; y < endY; y++) {
                        for (var x = startX; x < endX; x++) {
                            handler((y * width + x) << 2, x, y);
                        };
                    }
                },
                yDirection: function (data, width, startX, startY, endX, endY, handler) {
                    for (var x = startX; x < endX; x++) {
                        for (var y = startY; y < endY; y++) {
                            handler((y * width + x) << 2, x, y);
                        };
                    }
                }
            }
        };

        var getPixelPosition = function (width, x, y) {
            return (x + y * width) << 2;
        }

        var calculateInterpolation = function (data, width, x, y) {
            var x0 = Math.floor(x);
            var y0 = Math.floor(y);
            var x1 = Math.ceil(x);
            var y1 = Math.ceil(y);
            x = x - x0;
            y = y - y0;
            // rgba
            var rgba = new Array(4);
            for (var n = 0; n < 3; n++) {
                rgba[n] = (1 - x) * (1 - y) * data[getPixelPosition(width, x0, y0) + n] +
                    x * y * data[getPixelPosition(width, x1, y1) + n] +
                    (1 - x) * y * data[getPixelPosition(width, x0, y1) + n] +
                    x * (1 - y) * data[getPixelPosition(width, x1, y1) + n];
            }
            rgba[3] = 255;
            return rgba;
        }

        var Bilinear = function (data, width, height, scaleX, scaleY) {
            scaleX = scaleX || 1;
            scaleY = scaleY || scaleX;

            if (scaleX === 1 && scaleX === scaleY) {
                // return {
                //     data: data,
                //     width: width,
                //     height: height
                // };
                return new ImageData(data, width, height);
            }

            var nWidth = Math.floor(scaleX * width);
            var nHeight = Math.floor(scaleY * height);

            // 插值法是插空，下面计算真实插空的宽度
            scaleX = (nWidth - 1) / (width - 1);
            scaleY = (nHeight - 1) / (height - 1);

            var imageScaled = new Uint8ClampedArray(nWidth * nHeight * 4);

            util.each.xDirection(imageScaled, nWidth, 0, 0, nWidth, nHeight, function (i, x, y) {
                calculateInterpolation(data, width, x / scaleX, y / scaleY).map(function (color, n) {
                    imageScaled[i + n] = color;
                });
            });

            // return {
            //     data: imageScaled,
            //     width: nWidth,
            //     height: nHeight
            // }
            return new ImageData(imageScaled, nWidth, nHeight)
        }

        $.getJSON('data/2019032412_2019032516-fsp-surface-level-wrf-27km.json', function (res) {
            var result = res[0],
                idx = 0,
                width = result.header.nx, //x方向网格数
                height = result.header.ny; //y方向网格数

            //创建一个canvas画布
            var canvas = document.createElement('canvas');
            var context = canvas.getContext('2d');
            canvas.width = width;
            canvas.height = height;
            context.fillStyle = "rgba(255, 0, 0, 1)";
            context.fillRect(0, 0, width, height);
            var imageData = context.getImageData(0, 0, width, height);
            var data = imageData.data;

            //初始化图例
            var legend = new Legend();
            for (let y = 0; y < height; y++) {
                for (let x = 0; x < width; x++) {
                    var value = result.data[idx];
                    var rgba = legend.getColor(value).rgba;
                    var i = (y * width + x) * 4;
                    data[i] = rgba[0];
                    data[i + 1] = rgba[1];
                    data[i + 2] = rgba[2];
                    data[i + 3] = rgba[3];
                    idx++;
                }
            }
            context.putImageData(imageData, 0, 0);
            document.body.appendChild(canvas);

            var draw = Bilinear(data, width, height, window.innerWidth / width, window.innerHeight / height);
            var canvasScale = document.getElementById("canvasScale");
            canvasScale.width = draw.width;
            canvasScale.height = draw.height;
            var context = canvasScale.getContext('2d');
            context.putImageData(draw, 0, 0);
        });

        function Legend() {
            var options = this.options = {
                width: 400,
                height: 15,
                range: [0, 220],
                gradient: {
                    0.1: '#38a702',
                    0.4: '#b0e000',
                    0.7: '#ffaa01',
                    1.0: '#fe0000'
                }
            };

            this.init();
        }

        Legend.prototype.init = function () {
            var options = this.options;
            var canvas = this.canvas = document.createElement('canvas');
            var context = canvas.getContext('2d');
            canvas.width = options.width;
            canvas.height = options.height;
            var grad = context.createLinearGradient(0, 0, canvas.width, canvas.height);
            for (var gradient in options.gradient) {
                grad.addColorStop(gradient, options.gradient[gradient]);
            }
            context.fillStyle = grad;
            context.fillRect(0, 0, canvas.width, canvas.height);
            this.imageData = context.getImageData(0, 0, canvas.width, canvas.height);
        };

        Legend.prototype.d2Hex = function (d) {
            var hex = Number(d).toString(16);
            while (hex.length < 2) {
                hex = "0" + hex;
            }
            return hex.toUpperCase();
        };

        Legend.prototype.getRgbColor = function (point) {
            var imageData = this.imageData;
            var data = imageData.data;
            var i = ((point.y * this.canvas.width) + point.x) * 4;
            var rgba = [],
                color = '#',
                objRgbColor = {
                    "rgba": rgba,
                    "color": color
                };
            for (var j = 0; j < 3; j++) {
                rgba.push(data[i + j]);
                color += this.d2Hex(data[i + j]);
            }
            rgba.push(255);
            objRgbColor.color = color;
            return objRgbColor;
        };

        Legend.prototype.getColor = function (value) {
            var options = this.options;
            var colorValue = value - options.range[0];
            var point = {
                x: Math.round((colorValue * this.canvas.width) / (options.range[options.range.length - 1] -
                    options.range[0])),
                y: 1
            };
            return this.getRgbColor(point);
        };
    </script>
</body>

</html>